package com.mrd.util;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.beans.BeanUtils;

import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * 字符串工具类
 * Created by dengdc on 2016/10/24.
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils {

    /**
     * 使用反射清空字符串类型的属性前后的空格
     */
    public static void userReflectToTrimString(Object t, Class... loopClass) {
        Class tClass = t.getClass();

        List<Class> loopChain = new ArrayList<>();
        if (loopClass != null && loopClass.length > 0) {
            loopChain = Arrays.asList(loopClass);
        }
        Map<String, List<Object[]>> methodMap = getValidFieldMethods(tClass, loopChain);
        trimStringField(t, methodMap.get("stringFieldMethods"));
        trimCollectionField(t, methodMap.get("collectionFieldMethods"));
        trimArrayFieldMethods(t, methodMap.get("arrayFieldMethods"));
        trimCustomFieldMethods(t, methodMap.get("customFieldMethods"));
    }

    /**
     * 处理字符串字段
     *
     * @param t                  待处理对象
     * @param stringFieldMethods 字符串类型属性的读写方法
     */
    private static void trimStringField(Object t, List<Object[]> stringFieldMethods) {
        if(t == null){
            return;
        }
        for (Object[] methods : stringFieldMethods) {
            Method readMethod = (Method) methods[0];
            Method writeMethod = (Method) methods[1];
            try {
                Object val = readMethod.invoke(t);
                if (val != null) {
                    writeMethod.invoke(t, val.toString().trim());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 处理集合字段
     *
     * @param t                      待处理对象
     * @param collectionFieldMethods 自定义类型属性的读方法和循环链
     */
    private static void trimCollectionField(Object t, List<Object[]> collectionFieldMethods) {
        for (Object[] methods : collectionFieldMethods) {
            Method readMethod = (Method) methods[0];
            Class[] loopChain = (Class[]) methods[1];
            try {
                Object val = readMethod.invoke(t);
                if (val != null) {
                    Collection collection = Collection.class.cast(val);
                    for (Object o : collection) {
                        if(o == null){
                            continue;
                        }
                        userReflectToTrimString(o, loopChain);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 处理集合字段
     *
     * @param t                 待处理对象
     * @param arrayFieldMethods 数组类型属性的读方法和循环链
     */
    private static void trimArrayFieldMethods(Object t, List<Object[]> arrayFieldMethods) {
        for (Object[] methods : arrayFieldMethods) {
            Method readMethod = (Method) methods[0];
            Class[] loopChain = (Class[]) methods[1];
            try {
                Object val = readMethod.invoke(t);
                if (val != null) {
                    Object[] arr = Object[].class.cast(val);
                    for (Object o : arr) {
                        userReflectToTrimString(o, loopChain);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 处理集合字段
     *
     * @param t                  待处理对象
     * @param customFieldMethods 集合类型属性的读方法和循环链
     */
    private static void trimCustomFieldMethods(Object t, List<Object[]> customFieldMethods) {
        for (Object[] methods : customFieldMethods) {
            Method readMethod = (Method) methods[0];
            Class[] loopChain = (Class[]) methods[1];
            try {
                Object val = readMethod.invoke(t);
                if (val != null) {
                    userReflectToTrimString(val, loopChain);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获得所有待判断字段的read和write方法。
     */
    private static Map<String, List<Object[]>> getValidFieldMethods(Class tClass, List<Class> loopChain) {
        List<Field> fields = FieldUtils.getAllFieldsList(tClass);
        List<Object[]> stringFieldMethods = new ArrayList<>();
        List<Object[]> collectionFieldMethods = new ArrayList<>();
        List<Object[]> arrayFieldMethods = new ArrayList<>();
        List<Object[]> customFieldMethods = new ArrayList<>();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(tClass, field.getName());
            if (pd == null) {
                System.out.println(field + "没有get/set方法");
                continue;
            }
            Method readMethod = pd.getReadMethod();
            Method writeMethod = pd.getWriteMethod();
            if (String.class.equals(field.getType())) {
                stringFieldMethods.add(new Method[]{readMethod, writeMethod});
            } else if (field.getType().isAssignableFrom(List.class)) {
                Class[] classLoopChain = getNewLoopChain(loopChain, tClass);
                if (!constituteLoop(field, classLoopChain)) {
                    collectionFieldMethods.add(new Object[]{readMethod, classLoopChain});
                }
            } else if (field.getType().isAssignableFrom(Set.class)) {
                Class[] classLoopChain = getNewLoopChain(loopChain, tClass);
                if (!constituteLoop(field, classLoopChain)) {
                    collectionFieldMethods.add(new Object[]{readMethod, classLoopChain});
                }
            } else if (field.getType().isAssignableFrom(Object[].class)) {
                Class[] classLoopChain = getNewLoopChain(loopChain, tClass);
                if (!constituteLoop(field, classLoopChain)) {
                    arrayFieldMethods.add(new Object[]{readMethod, classLoopChain});
                }
            } else if (field.getType().isAssignableFrom(Map.class)) {
                //暂时没想到map类型的属性要怎么处理
            } else {
                Class[] classLoopChain = getNewLoopChain(loopChain, tClass);
                if (!constituteLoop(field, classLoopChain)) {
                    customFieldMethods.add(new Object[]{readMethod, classLoopChain});
                }
            }
        }
        Map<String, List<Object[]>> map = new HashMap<>();
        map.put("stringFieldMethods", stringFieldMethods);
        map.put("collectionFieldMethods", collectionFieldMethods);
        map.put("arrayFieldMethods", arrayFieldMethods);
        map.put("customFieldMethods", customFieldMethods);
        return map;
    }

    private static Class[] getNewLoopChain(List<Class> loopChain, Class thisClass) {
        List<Class> loopChain2 = new ArrayList<>();
        if (loopChain != null) {
            loopChain2.addAll(loopChain);
        }
        loopChain2.add(thisClass);
        return loopChain2.toArray(new Class[loopChain2.size()]);
    }

    /**
     * 判断是否构成循环
     *
     * @param judgeField 判断的field
     * @param loopChain  已有循环链
     */
    private static boolean constituteLoop(Field judgeField, Class... loopChain) {
        if (loopChain.length == 0) {
            return false;
        }
        if (judgeField.getType().isAssignableFrom(List.class) || judgeField.getType().isAssignableFrom(Set.class)) {
            Type type = judgeField.getGenericType();
            Type[] actualTypes = ((ParameterizedTypeImpl) type).getActualTypeArguments();
            if (actualTypes.length > 0) {
                Class actualClass = actualTypes[0].getClass();
                for (Class aClass : loopChain) {
                    if (aClass.equals(actualClass)) {
                        return true;
                    }
                }
            }
        } else if (judgeField.getType().isAssignableFrom(Object[].class)) {
            System.err.println("暂时不处理Array类型");
            return false; //暂时不处理Array类型
        } else if (judgeField.getType().isAssignableFrom(Map.class)) {
            System.err.println("暂时不处理Map类型");
            return true; //暂时不处理Map类型
        } else {
            for (Class aClass : loopChain) {
                if (aClass.equals(judgeField.getType())) {
                    return true;
                }
            }
        }
        return false;
    }

    public static String getUUID(){
        UUID uuid  =  UUID.randomUUID();
        return uuid.toString().replaceAll("\\-", "");
    }
}
